﻿namespace _4_NovaAdmin.Web.Core.ServiceExtensions;

public static class AuthorizationSetup
{
    public static void AddAuthorize(this IServiceCollection services, IConfiguration configuration)
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);
        // 从配置中绑定 JWTSettings
        var jwtSettings = configuration.GetSection("JWTSettings").Get<JWTOptions>();
        //策略鉴权
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Permission", policy => policy.Requirements.Add(new PolicyRequirement()));
        }).AddAuthentication(s =>
        {
            //添加JWT Scheme
            s.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            s.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            s.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        //添加jwt验证：
        .AddJwtBearer(options =>
        {
            // 保存令牌到内存中  
            options.SaveToken = true;
            // 不要求 HTTPS 元数据（生产环境中通常建议设置为 true）  
            options.RequireHttpsMetadata = false;

            // 配置令牌验证参数  
            options.TokenValidationParameters = new TokenValidationParameters()
            {
                // 验证签名密钥  
                ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey,
                // 使用对称密钥进行签名  
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey)),
                // 验证发行者  
                ValidateIssuer = jwtSettings.ValidateIssuer,
                // 有效的发行者  
                ValidIssuer = jwtSettings.ValidIssuer,
                // 验证受众  
                ValidateAudience = jwtSettings.ValidateAudience,
                // 有效的受众  
                ValidAudience = jwtSettings.ValidAudience,
                // 验证令牌的有效期  
                ValidateLifetime = jwtSettings.ValidateLifetime,
                // 设置时钟偏移量（允许的过期时间的宽限）  
                ClockSkew = TimeSpan.FromSeconds(jwtSettings.ClockSkew),
                // 要求令牌必须有过期时间  
                RequireExpirationTime = jwtSettings.RequireExpirationTime
            };
            options.Events = new JwtBearerEvents
            {
                //此处为权限验证失败后触发的事件
                OnChallenge = context =>
                {
                    //此处代码为终止.Net Core默认的返回类型和数据结果，这个很重要哦，必须
                    context.HandleResponse();

                    //自定义自己想要返回的数据结果，我这里要返回的是Json对象，通过引用Newtonsoft.Json库进行转换
                    var payload = JsonConvert.SerializeObject(new { code = 401, success = false, msg = "很抱歉，您无权访问该接口。" });
                    //自定义返回的数据类型
                    context.Response.ContentType = "application/json";
                    //自定义返回状态码，默认为401 我这里改成 200
                    context.Response.StatusCode = StatusCodes.Status200OK;
                    //context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    //输出Json数据结果
                    context.Response.WriteAsync(payload);
                    return Task.FromResult(0);
                }
            };
        });
    }
}
